package org.flowers.unbeaten.service.impl;


import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.flowers.unbeaten.base.entity.BaseEntity;
import org.flowers.unbeaten.base.entity.Department;
import org.flowers.unbeaten.base.entity.User;
import org.flowers.unbeaten.base.vo.DepartmentVo;
import org.flowers.unbeaten.exception.BusinessException;
import org.flowers.unbeaten.exception.code.BaseResponseCode;
import org.flowers.unbeaten.mapper.DepartmentMapper;
import org.flowers.unbeaten.mapper.UserMapper;
import org.flowers.unbeaten.service.IDepartmentService;
import org.flowers.unbeaten.util.Id;
import org.flowers.unbeaten.util.PageUtils;
import org.flowers.unbeaten.util.PageVo;
import org.flowers.unbeaten.util.PinYinUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 部门 服务实现类
 * </p>
 *
 * @author RyanWang
 * @since 2021-07-15
 */
@Service
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements IDepartmentService {

    @Autowired
    private IDepartmentService departmentService;

    @Autowired
    private DepartmentMapper departmentMapper;

    @Autowired
    private UserMapper userMapper;

    @Override
    public PageVo<Department> getDepartmentPageList(Department department, BaseEntity baseEntity) {
        PageHelper.startPage(baseEntity.getPage(), baseEntity.getLimit());
        List<Department> departments = departmentMapper.selectDepartments(department);
        return PageUtils.getPageVo(departments);
    }

    @Override
    public void add(Department department) {
        Department one = departmentService.getOne(Wrappers.<Department>lambdaQuery().eq(Department::getDepartmentName, department.getDepartmentName()));
        if (Objects.nonNull(one)) {
            throw new BusinessException(BaseResponseCode.DATA_ALREADY_EXISTS);
        }
        department.setDepartmentId(Id.generateId());
        // 设置部门code
        department.setDepartmentCode("D-" + PinYinUtils.getFirstSpell(department.getDepartmentName()));
        // 部门code转换成大写
        department.setDepartmentCode(department.getDepartmentCode().toUpperCase());
        departmentMapper.insert(department);
        List<DepartmentVo> departmentVos = getDepartmentPaths();
        departmentVos.forEach(departmentVo -> {
            if (department.getDepartmentId().equals(departmentVo.getDepartmentId())) {
                department.setPath(departmentVo.getPath());
                departmentService.updateById(department);
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(Department department) {
        Department source = departmentMapper.selectById(department.getDepartmentId());
        if (!source.getDepartmentName().equals(department.getDepartmentName())) {
            Department one = departmentService.getOne(Wrappers.<Department>lambdaQuery().eq(Department::getDepartmentName, department.getDepartmentName()));
            if (Objects.nonNull(one)) {
                throw new BusinessException(BaseResponseCode.DATA_ALREADY_EXISTS);
            }
        }
        department.setUpdateTime(LocalDateTime.now());
        // 设置组织机构code
        department.setDepartmentCode("D-" + PinYinUtils.getFirstSpell(department.getDepartmentName()));
        // 组织机构code转换成大写
        department.setDepartmentCode(department.getDepartmentCode().toUpperCase());
        this.departmentMapper.updateById(department);
        // 设置部门的层级关系
        List<DepartmentVo> departmentVos = departmentService.getDepartmentPaths();
        departmentVos.stream().forEach(departmentVo -> {
            if (department.getDepartmentId().equals(departmentVo.getDepartmentId())) {
                department.setPath(departmentVo.getPath());
                this.departmentService.updateById(department);
            }
        });
    }

    @Override
    public void delete(List<String> ids) {
        for (String id : ids) {
            Department department = departmentMapper.selectById(id);
            if (null == department) {
                throw new BusinessException(BaseResponseCode.DATA_ERROR);
            }
            List<Object> departmentIds = departmentMapper.selectObjs(Wrappers.<Department>lambdaQuery().select(Department::getDepartmentId).likeRight(Department::getDepartmentCode, department.getDepartmentCode()));
            List<User> users = userMapper.selectList(Wrappers.<User>lambdaQuery().in(User::getDepartmentId, departmentIds));
            if (!CollectionUtils.isEmpty(users)) {
                throw new BusinessException(BaseResponseCode.NOT_PERMISSION_DELETED_DEPARTMENT);
            }
            departmentMapper.deleteById(id);
        }
    }

    @Override
    public Department detail(String departmentId) {
        Department department = departmentMapper.selectById(departmentId);
        if (null == department) {
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        return department;
    }

    @Override
    public List<DepartmentVo> getDepartmentPaths() {
        List<DepartmentVo> departmentVoLinkedList = new LinkedList<>();
        List<DepartmentVo> departmentVoList = this.getChild();
        DepartmentVo departmentVo = new DepartmentVo();
        departmentVo.setDepartmentId("0");
        this.createDepartmentLevel(departmentVoLinkedList, departmentVoList, departmentVo);
        return departmentVoLinkedList;
    }

    @Override
    public List<DepartmentVo> getDepartmentAllTree() {
        List<Department> departments = departmentMapper.getAllDepartments();
        List<DepartmentVo> list = this.convertDepartmentToDepartmentVo(departments);
        DepartmentVo vo = new DepartmentVo();
        vo = this.convertListToTree(vo, list);
        return vo.getChildren();
    }

    /**
     * 根据父部门获取子部门
     * @return
     */
    private List<DepartmentVo> getChild() {
        List<Department> departments = departmentMapper.selectAllDepartments();
        List<DepartmentVo> departmentVos = new LinkedList<>();
        departments.forEach(department -> {
            if (!"0".equals(department.getChildren())) {
                departmentVos.add(this.initDepartment(department));
            }
        });
        return departmentVos;
    }

    /**
     * 生成部门层级结构
     * @param departmentVoLinkedList
     * @param departmentVoList
     * @param departmentVo
     */
    private void createDepartmentLevel(List<DepartmentVo> departmentVoLinkedList, List<DepartmentVo> departmentVoList, DepartmentVo departmentVo) {
        String path = null;
        for (DepartmentVo vo : departmentVoList) {
            if (vo.getParentId().equals(departmentVo.getDepartmentId())) {
                path = departmentVo.getDepartmentId().equals("0") ? vo.getDepartmentName() : departmentVo.getPath() + ">" + vo.getDepartmentName();
                vo.setPath(path);
                departmentVoLinkedList.add(vo);
                this.createDepartmentLevel(departmentVoLinkedList, departmentVoList, vo);
            }
        }
    }

    /**
     * 初始化部门
     * @param department
     * @return
     */
    private DepartmentVo initDepartment(Department department) {
        DepartmentVo vo = new DepartmentVo();
        vo.setDepartmentId(department.getDepartmentId());
        vo.setDepartmentName(department.getDepartmentName());
        vo.setDepartmentCode(department.getDepartmentCode());
        vo.setParentId(department.getParentId());
        vo.setPath(department.getPath());
        vo.setStatus(department.getStatus());
        return vo;
    }

    /**
     * 实体转换
     * @param departments
     * @return
     */
    private List<DepartmentVo> convertDepartmentToDepartmentVo(List<Department> departments) {
        List<DepartmentVo> list = new ArrayList<>();
        for (Department department : departments) {
            DepartmentVo vo = new DepartmentVo();
            vo.setDepartmentId(department.getDepartmentId());
            vo.setDepartmentCode(department.getDepartmentCode());
            vo.setDepartmentName(department.getDepartmentName());
            vo.setParentId(department.getParentId());
            vo.setStatus(department.getStatus());
            list.add(vo);
        }
        return list;
    }

    /**
     * List转Tree
     * @param vo
     * @param departmentVos
     * @return
     */
    private DepartmentVo convertListToTree(DepartmentVo vo, List<DepartmentVo> departmentVos) {
        List<DepartmentVo> treeList = new ArrayList<>();
        for (DepartmentVo tree : departmentVos) {
            for (DepartmentVo child : departmentVos) {
                if (Objects.equals(child.getParentId(), tree.getDepartmentId())) {
                    String path = "";
                    if (tree.getChildren() == null) {
                        tree.setChildren(new ArrayList<>());
                    }
                    // 拼接path
                    if (StringUtils.isNoneBlank(child.getParentId())) {
                        path = tree.getDepartmentName() + ">" + child.getDepartmentName();
                    } else {
                        path = tree.getPath() + ">" + child.getDepartmentName();
                    }
                    child.setPath(path);
                    tree.getChildren().add(child);
                }
            }
            if (Objects.equals(tree.getParentId(), "0")) {
                treeList.add(tree);
            }
            vo.setChildren(treeList);
        }
        return vo;
    }

}
